﻿#include "Entity.h"

CEntity::CEntity()
{
	m_posX = 0;
	m_posY = 0;
	m_vecX = 0;
	m_vecY = 0;
	m_accX = 0;
	m_accY = 0;
	m_posX_old = 0;
	m_posY_old = 0;
	m_LeftDeviation = 0;
	m_RightDeviation = 0;
	m_BotDeviation = 0;
	m_TopDeviation = 0;
	m_collsion = NONE;
	m_width = 0;
	m_heigth = 0;
}

CEntity::CEntity(float posX, float posY, int width, int height)
{
	m_posX = posX;
	m_posY = posY;
	m_vecX = 0;
	m_vecY = 0;
	m_accX = 0;
	m_accY = 0;
	m_LeftDeviation = 0;
	m_RightDeviation = 0;
	m_BotDeviation = 0;
	m_TopDeviation = 0;
	m_posX_old = posX;
	m_posY_old = posY;
	m_collsion = NONE;
	m_width = width;
	m_heigth = height;
}


float CEntity::getWCollision()
{
	return (m_width - m_LeftDeviation - m_RightDeviation);
}

float CEntity::getHCollision()
{
	return (m_heigth - m_TopDeviation - m_BotDeviation);
}

float CEntity::getPosXCollision()
{
	return (m_posX + m_LeftDeviation);
}

float CEntity::getPosYCollision()
{
	return (m_posY - m_TopDeviation);
}


RECT CEntity::getSweptBroadphaseBox(CEntity* entity)
{
	RECT broadphasebox;
	if (entity->getVecX() > 0)
	{
		broadphasebox.left = entity->getPosXCollision();
		broadphasebox.right = entity->getPosXCollision() + entity->getVecX() + entity->getWCollision();
	}
	else
	{
		broadphasebox.left = entity->getPosXCollision() + entity->getVecX();
		broadphasebox.right = entity->getPosXCollision() + entity->getWCollision();
	}
	if (entity->getVecY() > 0)
	{
		broadphasebox.top = entity->getPosYCollision() + entity->getVecY();
		broadphasebox.bottom = entity->getPosYCollision() - entity->getHCollision();
	}
	else
	{
		broadphasebox.top = entity->getPosYCollision();
		broadphasebox.bottom = entity->getPosYCollision() + entity->getVecY() - entity->getHCollision();
	}
	return broadphasebox;
}

DirectCollision CEntity::AABBCollision(CEntity* b, float& colTime)
{
	if (!Collision(getSweptBroadphaseBox(this), getSweptBroadphaseBox(b)))
	{
		return DirectCollision::NONE;
	}

	// xInvEtry: khoảng cách từ box1.x + width đến box2.x <vào va chạm>
	// xInvExit: khoảnh cách từ box2.x + width đến box1.x <ra va chạm>

	float xInvEntry, yInvEntry;
	float xInvExit, yInvExit;


	// find the distance between the objects on the near and far sides for both x and y
	if (this->getVecX() > 0.0f)
	{
		xInvEntry = b->getPosXCollision() - (this->getPosXCollision() + this->getWCollision());
		xInvExit = (b->getPosXCollision() + b->getWCollision()) - this->getPosXCollision();
	}
	else
	{
		xInvEntry = (b->getPosXCollision() + b->getWCollision()) - this->getPosXCollision();
		xInvExit = b->getPosXCollision() - (this->getPosXCollision() + this->getWCollision());
	}

	if (this->getVecY() > 0.0f)
	{
		yInvEntry = (b->getPosYCollision() - b->getHCollision()) - this->getPosYCollision();
		yInvExit = b->getPosYCollision() - (this->getPosYCollision() - this->getHCollision());
	}
	else
	{
		yInvEntry = b->getPosYCollision() - (this->getPosYCollision() - this->getHCollision());
		yInvExit = (b->getPosYCollision() - b->getHCollision()) - this->getPosYCollision();
	}

	// find time of collision and time of leaving for each axis (if statement is to prevent divide by zero)
	// THời gian va chạm và ra khỏi va chạm
	float xEntry, yEntry;
	float xExit, yExit;

	if (this->getVecX() == 0.0f)
	{
		// std::numeric_limits<float>::infinity() trả về số vô cùng
		xEntry = -std::numeric_limits<float>::infinity();
		xExit = std::numeric_limits<float>::infinity();
	}
	else
	{
		xEntry = xInvEntry / this->getVecX();
		xExit = xInvExit / this->getVecX();
	}

	if (this->getVecY() == 0.0f)
	{
		yEntry = -std::numeric_limits<float>::infinity();
		yExit = std::numeric_limits<float>::infinity();
	}
	else
	{
		yEntry = yInvEntry / this->getVecY();
		yExit = yInvExit / this->getVecY();
	}

	// find the earliest/latest times of collision
	// Thời gian nhanh nhất, và cuối cùng xảy ra va chạm, (xem va chạm trục nào trước, x hay y)
	float entryTime;
	float exitTime;
	if (xEntry > yEntry)
	{
		entryTime = xEntry;
	}
	else
	{
		entryTime = yEntry;
	}

	if (xExit < yExit)
	{
		exitTime = xExit;
	}
	else
	{
		exitTime = yExit;
	}

	// if there was no collision
	// Không xảy ra va chạm
	if (entryTime > exitTime || xEntry < 0.0f && yEntry < 0.0f || xEntry > 1.0f || yEntry > 1.0f)
	{
		if (Collision(getSweptBroadphaseBox(this), getSweptBroadphaseBox(b)))
		{
			if (Collision(this->getRect(), b->getRect())){

				if (getAccY() > 0)
				{
					return DirectCollision::BOTTOMACROSS;
				}
			}
			else
			{
				return DirectCollision::DONE;
			}
		}
		else
		{
			return DirectCollision::NONE;
		}
	}
	else // Va chạm
	{
		colTime = entryTime; // khoang thoi gian sap va cham
		// calculate normal of collided surface
		// Tính hướng trả về
		if ((xEntry < yEntry && xEntry > 0) || yEntry < 0)
		{
			if (xInvEntry < 0.0f)
			{
				return DirectCollision::RIGHT;
			}
			else
			{
				return DirectCollision::LEFT;
			}
		}
		else
		{
			if (yInvEntry <= 0.0f && this->getVecY() < 0.0f)
			{
				return DirectCollision::BOTTOM;
			}
			else
			{
				return DirectCollision::TOP;
			}

		}

	}
}
bool CEntity::Collision(RECT A, RECT B)
{
	return !(A.right < B.left || A.left > B.right || A.bottom > B.top || A.top < B.bottom);
}

void CEntity::setLeftDeviation(float leftDeviation)
{
	m_LeftDeviation = leftDeviation;
}

void CEntity::setRightDeviation(float rightDeviation)
{
	m_RightDeviation = rightDeviation;
}

void CEntity::setTopDeviation(float topDeviation)
{
	m_TopDeviation = topDeviation;
}

void CEntity::setBotDeviation(float bottomDeviation)
{
	m_BotDeviation = bottomDeviation;
}

void CEntity::setNoneDeviation()
{
	m_LeftDeviation = 0;
	m_RightDeviation = 0;
	m_BotDeviation = 0;
	m_TopDeviation = 0;
}

void CEntity::setDeviation(float leftDeviation, float rightDeviation, float topDeviation, float bottomDeviation)
{
	m_LeftDeviation = leftDeviation;
	m_RightDeviation = rightDeviation;
	m_BotDeviation = bottomDeviation;
	m_TopDeviation = topDeviation;
}


void CEntity::moveEnity()
{
	m_posX += m_vecX;
	m_posY += m_vecY;
}

void CEntity::moveEnity(float vecX, float vecY)
{

	m_posX += vecX;
	m_posY += vecY;
}

void CEntity::updateVec(float time)
{
	m_vecX += m_accX * time;
	m_vecY += m_accY * time;
}

void CEntity::setPhysic(float vecX, float vecY, float accX, float accY)
{
	m_vecY = vecX;
	m_vecX = vecY;
	m_accX = accX;
	m_accY = accY;
}

void CEntity::stopPhysic()
{
	m_vecY = 0;
	m_vecX = 0;
	m_accX = 0;
	m_accY = 0;
}
void CEntity::stopVec()
{
	m_vecY = 0;
	m_vecX = 0;
}
RECT CEntity::getRect()
{
	RECT x;
	x.left = m_posX;
	x.top = m_posY;
	x.right = x.left + getWCollision();
	x.bottom = x.top - getHCollision();

	return x;
}

void CEntity::setPostion(D3DXVECTOR2 x)
{
	m_posX = x.x;
	m_posY = x.y;
}
void CEntity::setPostion(float posX, float posY)
{
	m_posX = posX;
	m_posY = posY;
}


CEntity::~CEntity()
{

}